/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.tnmk.worktime.service;

import java.util.List;
import org.joda.time.DateTime;
import org.tnmk.worktime.service.dao.entry.SessionEntry;
import org.tnmk.worktime.service.dao.entry.SessionType;
import org.tnmk.worktime.service.dao.entry.SpendEntry;
import org.tnmk.worktime.utils.TimeUtils;

/**
 *
 * @author Administrator
 */
public class CalculatorService {

  private static final CalculatorService INSTANCE = new CalculatorService();
  public static CalculatorService getInstance() {
    return INSTANCE;
  }

  public static boolean isOffDay(DateTime time) {
    int dayOfWeek = time.getDayOfWeek();
    for (int offDay : SessionService.OFF_DAYS) {
      if (offDay == dayOfWeek) {
        return true;
      }
    }
    return false;
  }

  public long reckonSpend(SessionEntry entry) {
    long rs = 0;
    for (SpendEntry spend : entry.getMoneySpend().getItems()) {
      rs += (spend.getCost() != null ? spend.getCost() : 0);
    }
    return rs;
  }

  public long reckonSpend(List<SessionEntry> sessions) {
    long rs = 0;
    for (SessionEntry session : sessions) {
      long sessionSpend = this.reckonSpend(session);
      rs += sessionSpend;
    }
    return rs;
  }

  public static boolean isWorkDay(SessionEntry entry) {
    return entry.getType() == SessionType.Work;
  }

  /**
   * @param model
   */
  public void reckonWorkedHours(SessionEntry model) {
    float rs;
    if (!isWorkDay(model)) {
      rs = 0;
    } else {
      DateTime inTime = model.getInTime();
      DateTime outTime = model.getOutTime();
      if (outTime.isBefore(model.getBreakBeginTime())) {
        rs = TimeUtils.calculatePeriod(inTime, outTime);
      } else if (outTime.isBefore(model.getBreakEndTime())) {
        rs = TimeUtils.calculatePeriod(inTime, model.getBreakBeginTime());
      } else {
        if (inTime.isAfter(model.getBreakEndTime())) {
          rs = TimeUtils.calculatePeriod(inTime, outTime);
        } else if (inTime.isAfter(model.getBreakBeginTime())) {
          rs = TimeUtils.calculatePeriod(model.getBreakEndTime(), outTime);
        } else {
          float beforeBreak = TimeUtils.calculatePeriod(inTime, model.getBreakBeginTime());
          float afterBreak = TimeUtils.calculatePeriod(model.getBreakEndTime(), outTime);
          rs = beforeBreak + afterBreak;
        }
      }
    }
    model.setWorkedHours(rs);
//    return rs;
  }

  /**
   * @param sessions
   * @return workedHoursHistory
   */
  public float reckonWorkedHours(List<SessionEntry> sessions) {
    float rs = 0;
    for (SessionEntry session : sessions) {
      this.reckonWorkedHours(session);
      float iworkHours = session.getWorkedHours();
      rs += iworkHours;
    }
    return rs;
  }

  /**
   * Must call loadHistory and loadThisWeekHistory before calling this method.
   *
   * @param weekWorkedHoursHistory
   * @param sessions
   * @param exceptToday don't calculate workedHours of this session. Note:
   * except must be in sessions list, otherwise, the result can be wrong
   * calculated.
   * @return avgRequiredWorkedHours
   */
  public float reckonAvgRequiredHours(float weekWorkedHoursHistory,
          List<SessionEntry> sessions, SessionEntry exceptToday) {
    int weekWorkedDaysExceptToday = sessions.size();
    float weekWorkedHoursExceptToday = weekWorkedHoursHistory;
    if (exceptToday != null) {
      weekWorkedDaysExceptToday -= 1;
      weekWorkedHoursExceptToday -= exceptToday.getWorkedHours();
    }
    int remainDays = SessionService.WORK_DAYS_IN_WEEK - weekWorkedDaysExceptToday;
    if (weekWorkedHoursExceptToday >= SessionService.WORK_HOURS_IN_WEEK) {
      return 0;
    }
    float remainHours = SessionService.WORK_HOURS_IN_WEEK - weekWorkedHoursExceptToday;
    float rs = (float) remainHours / remainDays;
    return rs;
  }

  public void reckonOutTime(SessionEntry model) {
    if (isWorkDay(model)) {
      DateTime outTime;
      DateTime inTime = model.getInTime();
      DateTime breakBeginTime = model.getBreakBeginTime();
      DateTime realBeginWorkTime = inTime;
      DateTime breakEndTime = model.getBreakBeginTime();
      if (inTime.isAfter(breakBeginTime)) {
        model.setLeaveHours(4);//automatic set leave half day when you begin after break time
        model.setMustWorkHoursToday(model.getExpectWorkHoursToday() - model.getLeaveHours());
        if (inTime.isBefore(breakEndTime)) {
          realBeginWorkTime = breakEndTime;
        }
        outTime = TimeUtils.addHours(realBeginWorkTime, model.getMustWorkHoursToday());
      } else {
        model.setLeaveHours(0);
        model.setMustWorkHoursToday(model.getExpectWorkHoursToday() - model.getLeaveHours());
        float breakHours = TimeUtils.calculatePeriod(model.getBreakBeginTime(), model.getBreakEndTime());
        outTime = TimeUtils.addHours(realBeginWorkTime, model.getMustWorkHoursToday());
        outTime = TimeUtils.addHours(outTime, breakHours);
      }
      model.setExpectedOutTime(outTime);
    } else {
      model.setExpectWorkHoursToday(0);
      model.setMustWorkHoursToday(0);
      model.setExpectedOutTime(DateTime.now());
    }
  }
}
